0289. 生命游戏【中等】
1. 📝 题目描述
根据 百度百科,游戏,简 生命,国数约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为 胞 (ve),或 0 即为 死细胞 ead 每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
- 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
- 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
- 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
- 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是 发。给你 m x n 网格面板 board 的当前状态,返回下一个状态。
给定当前 board 的状态,brd 到下一个状态。
你要返回任何东西。
- 示例 1:

txt
输入:board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
输出:[[0,0,0],[1,0,1],[0,1,1],[0,1,0]]1
2
2
- 示例 2:

txt
输入:board = [[1,1],[1,0]]
输出:[[1,1],[1,1]]1
2
2
提示:
m == board.lengthn == board[i].length1 <= m, n <= 25board[i][j]为0或1
进阶:
- 你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
- 本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?
2. 🎯 s.1 - 原地标记
c
void gameOfLife(int** board, int boardSize, int* boardColSize) {
int m = boardSize, n = boardColSize[0];
int dirs[] = {-1, 0, 1};
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int live = 0;
for (int di = 0; di < 3; di++) {
for (int dj = 0; dj < 3; dj++) {
if (dirs[di] == 0 && dirs[dj] == 0) continue;
int ni = i + dirs[di], nj = j + dirs[dj];
if (ni >= 0 && ni < m && nj >= 0 && nj < n && (board[ni][nj] & 1)) live++;
}
}
if (board[i][j] & 1) {
if (live == 2 || live == 3) board[i][j] |= 2;
} else {
if (live == 3) board[i][j] |= 2;
}
}
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
board[i][j] >>= 1;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
js
/**
* @param {number[][]} board
* @return {void}
*/
var gameOfLife = function (board) {
const m = board.length,
n = board[0].length
const dirs = [-1, 0, 1]
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
let live = 0
for (const di of dirs) {
for (const dj of dirs) {
if (di === 0 && dj === 0) continue
const ni = i + di,
nj = j + dj
if (ni >= 0 && ni < m && nj >= 0 && nj < n && board[ni][nj] & 1)
live++
}
}
// 第二位记录下一状态
if (board[i][j] & 1) {
if (live === 2 || live === 3) board[i][j] |= 2
} else {
if (live === 3) board[i][j] |= 2
}
}
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
board[i][j] >>= 1
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
py
class Solution:
def gameOfLife(self, board: List[List[int]]) -> None:
m, n = len(board), len(board[0])
for i in range(m):
for j in range(n):
live = 0
for di in (-1, 0, 1):
for dj in (-1, 0, 1):
if di == 0 and dj == 0:
continue
ni, nj = i + di, j + dj
if 0 <= ni < m and 0 <= nj < n and (board[ni][nj] & 1):
live += 1
if board[i][j] & 1:
if live in (2, 3):
board[i][j] |= 2
else:
if live == 3:
board[i][j] |= 2
for i in range(m):
for j in range(n):
board[i][j] >>= 11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 时间复杂度:
,其中 和 是矩阵的行数和列数 - 空间复杂度:
,原地修改
算法思路:
- 用第二位记录下一状态:低位是当前状态,高位是下一状态
- 统计每个细胞周围活细胞数(用
& 1取当前状态),根据规则设置高位 - 最后统一右移一位得到最终状态